﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Services.Extractors.MarketSmith;
using StockFinder.Model;
using log4net;
using System.IO;
using StockFinder.DataAccess;

namespace StockFinder.Services.Engines
{
    /// <summary>
    /// Extracts current IBD Ratings and then saves to CSV and database object
    /// </summary>
    public class IBDRatingDatabaseUpdater
    {
        private static readonly ILog _Log = LogManager.GetLogger(typeof(IBDRatingDatabaseUpdater));        

        public void Run()
        {
            //1. extract IBD ratings
            MarketSmithIBDCompositeExtractor extractor = new MarketSmithIBDCompositeExtractor();

            _Log.DebugFormat("Getting IBD Ratings");

            Tuple<int, List<IBDRatings>> result = extractor.GetIBDRatingsFromMarketSmith();

            Cache.IBDRatingsList = result.Item2;

            //check we have expected number
            if (result.Item1 != Cache.IBDRatingsList.Count)
            {
                _Log.WarnFormat("There are {0} items in the list but expected {1}", result.Item1, Cache.IBDRatingsList.Count);
            }

            _Log.DebugFormat("Saving IBD ratings to CSV");

            //save as CSV
            StringBuilder csvOutput = new StringBuilder("Symbol,EPS Rating,RS Rating,Industry Group RS,SMR Rating,A/D Rating,Composite Rating,Type,Is ETF/Closed-End Fund,Is ETF,Average True Range,52 Week High,52 Week Low");

            csvOutput.AppendLine();

            foreach (var item in Cache.IBDRatingsList)
            {
                csvOutput.AppendFormat("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13}",
                    item.Symbol,item.EPS,item.RelativeStrength,item.GroupRSRating,item.SMR,
                    item.AccDist,item.IBDComposite,item.StockType,item.IsETFOrClosedEndFund,item.IsETF,
                    item.AverageTrueRange,item.YearHigh,item.YearLow, Environment.NewLine);                                
            }

            try
            {
                string fileName = "C:\\Data\\IBD\\Ratings\\" + DateTime.Today.AddDays(-1).ToString("yyyyMMdd") + ".csv";

                for (int i = 1; File.Exists(fileName); i++ )
                {
                    fileName = "C:\\Data\\IBD\\Ratings\\" + DateTime.Today.AddDays(-1).ToString("yyyyMMdd") + "[" + i.ToString() + "]" + ".csv";
                }
                
                File.WriteAllText(fileName, csvOutput.ToString());
            }
            catch (Exception exception)
            {
                _Log.ErrorFormat("An unexpected error occurred writing to CSV file {0}", exception);                
            }

            /* SAVE RATINGS INTO DATABASE */

            _Log.InfoFormat("Saving IBD Ratings into database");

            try
            {
                //save to database
                foreach (var rating in Cache.IBDRatingsList)
                {
                    IBDDataAccess.InsertIBDRating(rating);
                }
            }
            catch (Exception exception)
            {
                _Log.ErrorFormat("Error inserting IBD Rating into database -> {0}", exception);
            }            
        }

        public void LoadFromFile()
        {
            DirectoryInfo info = new DirectoryInfo(ApplicationConfiguation.IbdRatingsDirectory);

            if (info.EnumerateFiles().Count() > 0)
            {
                string fileInfo = info.EnumerateFiles().OrderBy(i => i.Name).Last().FullName;

                _Log.DebugFormat("File to be used {0}", fileInfo);

                //try and load in symbol list from saved ratings
                var ratingsText = string.Empty;
                //load ratings list
                using (StreamReader reader = new StreamReader(fileInfo))
                {
                    ratingsText = reader.ReadToEnd();
                }

                var lines = ratingsText.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();

                var ratingsList = new List<IBDRatings>();                

                foreach (var line in lines.Skip(1))
                {
                    var cells = line.Split(new char[] { ',' });

                    ratingsList.Add(new IBDRatings()
                    {
                        Symbol = cells[0],
                        EPS = Convert.ToInt32(cells[1]),
                        RelativeStrength = Convert.ToInt32(cells[2]),
                        GroupRSRating = cells[3],
                        SMR = cells[4],
                        AccDist = cells[5],
                        IBDComposite = Convert.ToInt32(cells[6]),
                        StockType = cells[7],
                        IsETFOrClosedEndFund = Convert.ToBoolean(cells[8]),
                        IsETF = Convert.ToBoolean(cells[9]),
                        AverageTrueRange = Convert.ToDecimal(cells[10]),
                        YearHigh = Convert.ToDecimal(cells[11]),
                        YearLow = Convert.ToDecimal(cells[12]),
                    });                                        
                }

                _Log.DebugFormat("Loaded {0} IBD Ratings", ratingsList.Count);

                Cache.IBDRatingsList = ratingsList;
            }
        }
    }
}
